#ifndef BASE_MEMORY_POOL_H
#define BASE_MEMORY_POOL_H

#include "base_noncopyable.h"
#include <stddef.h>
#include <stdint.h>
#include <mutex>
#include <chrono>
#include <string>
#include <unordered_map>
#include <memory>

namespace El {
namespace Base {

/**
 * @brief 内存池类，提供高效的内存分配和释放
 *
 * 该内存池实现了一个灵活的内存管理策略，支持非顺序释放内存和顺序循环分配。
 * 内存池会自动跟踪已分配的内存块，并在释放时验证内存块的有效性。
 * 支持64位内存地址，可以处理大于4GB的内存。
 * 注意：内存分配是顺序的，从当前位置开始分配，如果当前位置无法分配，
 * 则尝试从头开始分配，但不会跳过已分配的内存区域。
 */
class MemoryPool {
    DISALLOW_COPY_AND_MOVE(MemoryPool);

public:
    /**
     * @brief 获取内存池实例
     *
     * @param name 内存池实例名称，不同名称对应不同实例
     * @return MemoryPool& 内存池实例引用
     */
    static MemoryPool &GetInstance(const std::string &name = "default");

    /**
     * @brief 释放指定名称的内存池实例
     *
     * @param name 要释放的内存池实例名称
     * @return 是否成功释放
     */
    static bool ReleaseInstance(const std::string &name);

    /**
     * @brief 释放所有内存池实例
     */
    static void ReleaseAllInstances();
    /**
     * @brief 构造函数
     */
    MemoryPool();

    /**
     * @brief 析构函数
     */
    ~MemoryPool();

    /**
     * @brief 初始化内存池
     *
     * @param totalSize 内存池总大小(字节)
     * @param blockAlign 内存块对齐大小(字节)，默认为8字节对齐
     * @return 是否初始化成功
     */
    bool Init(uint64_t totalSize, uint64_t blockAlign = 8);

    /**
     * @brief 申请内存块
     *
     * @param size 申请的内存块大小(字节)
     * @return 返回申请到的内存块指针，如果申请失败返回nullptr
     *
     * 当内存池剩余空间不足以满足申请时，会返回失败。
     * 申请的内存块保证是连续的，不会跨越缓冲区边界。
     * 如果申请大小超过内存池总大小，则返回nullptr。
     * 内存分配是顺序的，从当前位置开始分配，如果当前位置无法分配，
     * 则尝试从头开始分配，但不会跳过已分配的内存区域。
     */
    void *Allocate(uint64_t size);

    /**
     * @brief 释放内存块
     *
     * @param ptr 要释放的内存块指针
     * @return 是否释放成功
     *
     * 释放之前通过Allocate申请的内存块。
     * 支持非顺序释放内存块，可以按任意顺序释放。
     * 如果ptr不是有效的内存块指针，则返回false。
     */
    bool Free(void *ptr);

    /**
     * @brief 获取内存池总大小
     *
     * @return 内存池总大小(字节)
     */
    uint64_t GetTotalSize() const;

    /**
     * @brief 获取内存池剩余可用大小
     *
     * @return 内存池剩余可用空间(字节)
     */
    uint64_t GetAvailableSize() const;

    /**
     * @brief 获取已用内存大小
     *
     * @return 已用内存大小(字节)
     */
    uint64_t GetUsedSize() const;

    /**
     * @brief 重置内存池
     *
     * 将内存池重置为初始状态，所有指针归零
     */
    void Reset();

    /**
     * @brief 打印内存池状态信息
     *
     * @param detailed 是否打印详细信息，包括每个已分配内存块的详情
     *
     * 打印内存池的基本状态信息，包括总大小、已用大小、可用大小、
     * 当前分配位置、内存块对齐大小、已分配内存块数量等。
     * 如果detailed为true，还会打印每个已分配内存块的详细信息。
     */
    void DumpStatus(bool detailed = false) const;

private:
    /**
     * @brief 检查指定区域是否与已分配区域重叠
     *
     * @param start 区域起始偏移量
     * @param size 区域大小
     * @return 是否有重叠
     */
    bool IsRegionOverlapping(uint64_t start, uint64_t size);

    /**
     * @brief 查找可用的内存区域
     *
     * @param size 需要分配的大小
     * @param outOffset 输出参数，找到的可用区域偏移量
     * @return 是否找到可用区域
     */
    bool FindAvailableRegion(uint64_t size, uint64_t &outOffset);

    /**
     * @brief 更新内存分配速率统计
     *
     * @param size 新分配的内存大小
     */
    void UpdateAllocationRate(uint64_t size);

    struct Internal;
    Internal *internal_;
    std::mutex mutex_; // 互斥锁，保证线程安全

    // 内存使用统计相关
    uint64_t totalAllocatedSize_;                                 // 历史累计分配的内存总量
    uint64_t allocationsInCurrentWindow_;                         // 当前时间窗口内分配的内存量
    uint64_t currentAllocationRate_;                              // 当前计算的每秒分配速率
    std::chrono::steady_clock::time_point lastUpdateTime_;        // 上次更新速率的时间点
    static constexpr std::chrono::seconds rateUpdateInterval_{1}; // 速率更新间隔

    // 静态成员，用于管理多个内存池实例
    static std::mutex instancesMutex_;
    static std::unordered_map<std::string, std::unique_ptr<MemoryPool>> instances_;
};

} // namespace Base
} // namespace El

#endif // BASE_MEMORY_POOL_H
